home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: TextPrimitives.c Contains: QuickDraw GX to PostScript conversion code. This file contains routines necessary for translating text and glyph primitives into PostScript Version: Technology: Quickdraw GX 1.1.x Copyright: © 1991-1997 by Apple Computer, Inc., all rights reserved. */ #include "GXToPSBuildConfig.h" #include <GXGraphics.h> #include "GXGraphicsPriv.h" #include <GXEnvironment.h> #include "GXToPostScript.h" #include "IOUtilities.h" #include "RDUtil.h" #include "FontHandler.h" #include "PublicPostScriptIE.h" #include "private.h" #include "PSIEResources.h" #include "GXErrors.h" #include "ShapeUtilities.h" #include <String.h> #ifdef resumeLabel #undef resumeLabel #endif #define resumeLabel(exception) #define kVerticalStyleMarkTag 'vsmk' OSErr ResolveJustifiedText(TIEGlobalsHdl hIEGlobals, gxShape theShape, TGlyphDataRec *pGlyphData); OSErr ResolveJustifiedText(TIEGlobalsHdl hIEGlobals, gxShape theShape, TGlyphDataRec *pGlyphData) { OSErr status = noErr; gxStyle shapeStyle = GXGetShapeStyle(theShape); long i, counter; Boolean allLeftJustified = true; Boolean checkedShapeStyle = false; gxPoint *positions; #pragma unused(hIEGlobals) /* walk through all the style runs, looking for some justification besides left */ for( i = 0; i < pGlyphData->nStyles; i++ ) { gxStyle tempStyle; if( (tempStyle = pGlyphData->styles[i]) == nil ) { if( checkedShapeStyle ) continue; tempStyle = shapeStyle; checkedShapeStyle = true; } if( GXGetStyleJustification(tempStyle) != gxLeftJustify ) { allLeftJustified = false; break; } } if( allLeftJustified ) return noErr; if( pGlyphData->absPositions == nil ) { status = PrNewPtr((Ptr*)&positions, sizeof(gxPoint) * (pGlyphData->nChars + 1)); nrequire(status, failed_NewPtr); GXGetGlyphMetrics(theShape, positions, nil, nil); } else { positions = pGlyphData->absPositions; }//end if /* copy the absolute positions into the regular positions and set all the advance bits to have absolute points */ BlockMove((Ptr)positions, (Ptr)pGlyphData->positions, pGlyphData->nChars * sizeof(gxPoint)); counter = pGlyphData->nChars >> 5; //This is the number of long words. if( (counter << 5) < pGlyphData->nChars ) //make sure we didn't round down. ++counter; for( i = 0; i < counter; ++i ) { pGlyphData->advanceBits[i] = 0xFFFFFFFF; } if (positions != pGlyphData->absPositions) DisposePtr((Ptr)positions); failed_NewPtr: return (status); } //<FF> /****************************************** ResolveVerticalText: Routine modifies the positions of any glyphs that are in style runs that have the vertical-text bit set so that those glyphs draw correctly in the horizontal-only model that PostScript uses. The data is modified in a glyph-data record that has all of the glyph data previously loaded into it. ******************************************/ OSErr ResolveVerticalText(TIEGlobalsHdl hIEGlobals, gxShape theShape, TGlyphDataRec *pGlyphData); OSErr ResolveVerticalText(TIEGlobalsHdl hIEGlobals, gxShape theShape, TGlyphDataRec *pGlyphData) { OSErr status; TIEGlobalsPtr pGlobals; gxShape shapeCopy; long i, glyphCount; unsigned long *advLong, advMask; register short j; long nChars; gxTag changedTag; // We will tag styles we change so we know we changed them. gxStyle *pStyle; // pointer to next style. short *pRun; // Pointer to next run. gxPoint *pPos; // Pointer to next position. gxPoint *pAbsPos; // Pointer to next absolute position. unsigned long *newAdvBits; // New advance bits. long workSize; // size of work space we will need. long advSize; // Size of advance bits array of longs. gxRectangle *boxesH, *boxesV; // Bounding boxes for vertical and horizontal cases. gxRectangle *pBoxH, *pBoxV; gxPoint *absPositions; // Absolute positions for glyphs. gxTextAttribute theAttributes; /** First do a quick check to see if there are any vertical runs **/ pStyle = pGlyphData->styles; for (i = pGlyphData->nStyles - 1 ; i >= 0; --i) { if( *pStyle && (GXGetStyleTextAttributes(*pStyle) & gxVerticalText) ) break; else if ((*pStyle == nil) && (GXGetStyleTextAttributes(GXGetShapeStyle(theShape)) & gxVerticalText)) break; pStyle++; }//end for if (i == -1) // no vertical style runs, just get out of here. return(noErr); /*** There was at least one vertical style! Resovle positions ***/ nChars = pGlyphData->nChars; /****** First allocate all the memory we will need: for 2 sets of bounding boxes, advance bits, and, if we don't already have them, the absolute positions for each glyph. ****/ workSize = nChars * 2 * sizeof(gxRectangle); // room for bounding boxes. advSize = pGlyphData->nChars >> 5; //This is the number of long words. if ((advSize << 5) < pGlyphData->nChars) //make sure we didn't round down. advSize++; workSize += sizeof(long) * advSize; if (pGlyphData->absPositions == nil) workSize += (nChars + 1) * sizeof(gxPoint); // For absolute positions. else absPositions = pGlyphData->absPositions; nrequire(status = PSSetWorkSpaceSize(hIEGlobals, workSize), failed_SetSize); pGlobals = *hIEGlobals; HLock(pGlobals->hWorkSpace); // We will be buffering this data so lock it. /** Point at the workspace **/ { Ptr p = *(pGlobals->hWorkSpace); boxesH = (gxRectangle*)p; p += nChars * sizeof(gxRectangle); boxesV = (gxRectangle*)p; p += nChars * sizeof(gxRectangle); newAdvBits = (unsigned long*)p; p += advSize * sizeof(unsigned long); /* Set the advance bits to 1 */ advLong = newAdvBits; for (i = 0; i < advSize; ++i) *advLong++ = 0xFFFFFFFF; if (pGlyphData->absPositions == nil) { absPositions = (gxPoint*)p; GXGetGlyphMetrics(theShape, absPositions, boxesV, nil); } else { GXGetGlyphMetrics(theShape, nil, boxesV, nil); // already got positions in GlyphDataIntoWorkSpace }//end if }//end block /**** Now turn off vertical bit for all style runs that have it to get other bounding boxes, tag the styles we changed. ****/ changedTag = GXNewTag(kVerticalStyleMarkTag, 0, nil); // Make a tag to mark styles with. pStyle = pGlyphData->styles; for (i = pGlyphData->nStyles - 1 ; i >= 0; --i) { theAttributes = GXGetStyleTextAttributes(*pStyle); if (theAttributes & gxVerticalText) { theAttributes &= ~gxVerticalText; GXSetStyleTags(*pStyle, kVerticalStyleMarkTag, 0, 0, 1, &changedTag); GXSetStyleTextAttributes(*pStyle, theAttributes); }//end if ++pStyle; }//end for GXDisposeTag(changedTag); /**** Now get the bounding boxes for the non-vertical glyphs: 1. Make a copy of the shape so we don't corrupt it. 2. Make this version have absolute positions for all glyphs 3. Get the bounding boxes ****/ shapeCopy = GXCopyToShape(nil, theShape); GXSetGlyphs(shapeCopy, nil, nil, absPositions, (long*)newAdvBits, nil, nil, nil); // we need to use absolute positions for each glyph to get correct metrics. GXChangedShape(shapeCopy); GXGetGlyphMetrics(shapeCopy, nil, boxesH, nil); GXDisposeShape(shapeCopy); nrequire(status = GXGetGraphicsError(nil), failed_CopyIt); /*** Now we have bounding boxes for the vertical case as well as the horizontal case: Modify the positions by the difference between the vertical box location (top, left) and the horizontal box location. ***/ pRun = pGlyphData->runs; pPos = pGlyphData->positions; pAbsPos = absPositions; pBoxH = boxesH; pBoxV = boxesV; pStyle = pGlyphData->styles; glyphCount = 0; for (i = 1; i <= pGlyphData->nStyles; ++i) { if (GXGetStyleTags(*pStyle, kVerticalStyleMarkTag, 1, gxSelectToEnd, nil) ) { theAttributes = GXGetStyleTextAttributes(*pStyle); GXSetStyleTextAttributes(*pStyle, theAttributes | gxVerticalText); // put it back to be clean. j = glyphCount / 32; // Get offset into advance array. advLong = pGlyphData->advanceBits + j; // Get address of advance bits. advMask = 0x80000000U >> (glyphCount - j*32); // Offset mask for remainder. /** Modify positions for this run and set each advance bit **/ for (j = *pRun - 1; j >= 0; --j) { pAbsPos->x -= (pBoxH->left - pBoxV->left); pAbsPos->y -= (pBoxH->top - pBoxV->top); pPos->x = pAbsPos->x; pPos->y = pAbsPos->y; /** Set the advance bit for this glyph **/ *advLong |= advMask; if ((advMask >>= 1) == 0) { ++advLong; advMask = 0x80000000; }//end if ++pAbsPos; ++pPos; ++pBoxV; ++pBoxH; }//end for /** Make sure the glyph immediately following this run also has absolute position **/ if (i < pGlyphData->nStyles) { // don't do it for the last style run. *advLong |= advMask; pPos->x = pAbsPos->x; pPos->y = pAbsPos->y; }//end if } else { pAbsPos += *pRun; pPos += *pRun; pBoxH += *pRun; pBoxV += *pRun; }//end if glyphCount += *pRun; ++pStyle; ++pRun; }//end for failed_CopyIt: status = PSReleaseWorkSpace(hIEGlobals); ncheck(status); failed_SetSize: return(status); }//ResolveVerticalText //<FF> /****************************************** GlyphDataIntoWorkSpace: Function loads data from the Glyph Shape into specified parameter block (which really will point into the workspace), the workspace is locked upon successful completion of this routine. The client must call PSReleaseWorkSpace when done with the glyph data. ********************************************/ OSErr GlyphDataIntoWorkSpace(TIEGlobalsHdl hIEGlobals, gxShape theShape, TGlyphDataRec *pGlyphData); OSErr GlyphDataIntoWorkSpace(TIEGlobalsHdl hIEGlobals, gxShape theShape, TGlyphDataRec *pGlyphData) { OSErr status; long totalSize; long size; gxTag fhGlyphTag; gxTag fh2byteTag; TIEGlobalsPtr pGlobals; Ptr p; /* Get the tag containing modified glyph code data */ GXGetShapeTags(theShape, fhTextDataTag, 1, 1, &fhGlyphTag); pGlyphData->byteCount = GXGetTag(fhGlyphTag, nil, nil); /** Get statistics on the glyph shape **/ GXGetGlyphs(theShape, &(pGlyphData->nChars), nil, nil, nil, nil, &(pGlyphData->nStyles), nil, nil); /** Space needed for Font Handleur 8/16 data **/ if (GXGetShapeTags(theShape, fh1or2byteTag, 1, 1, nil) ) { GXGetShapeTags(theShape, fh1or2byteTag, 1, 1, &fh2byteTag); pGlyphData->fhUserDataSize = GXGetTag(fh2byteTag, nil, nil); } else { pGlyphData->fhUserDataSize = 0; }//end if /** Compute the total work space size we will need **/ totalSize = pGlyphData->byteCount; totalSize += pGlyphData->nChars * ( sizeof(gxPoint) + //the positions sizeof(gxPoint) + //the tangents sizeof(short)); //the glyphs totalSize += pGlyphData->nStyles * ( sizeof(gxStyle) + //the styles sizeof(short) ); //the style runs totalSize += pGlyphData->fhUserDataSize; /** For level-2, we need absolute positions for every glyph in case we must use xyshow **/ if ((*hIEGlobals)->params.languageLevel > 1) totalSize += (pGlyphData->nChars + 1) * sizeof(gxPoint); /* Compute the space needed for the advance bits */ size = pGlyphData->nChars >> 5; //This is the number of long words. if ((size << 5) < pGlyphData->nChars) //make sure we didn't round down. size++; totalSize += sizeof(long) * size; nrequire(status = PSSetWorkSpaceSize(hIEGlobals, totalSize), failed_SetSize); pGlobals = *hIEGlobals; HLock(pGlobals->hWorkSpace); // We will be buffering this data so lock it. /** Now point the fields of the glyph param block into the work space **/ p = *(pGlobals->hWorkSpace); pGlyphData->positions = (gxPoint*)p; p += pGlyphData->nChars * sizeof(gxPoint); pGlyphData->tangents = (gxPoint*)p; p += pGlyphData->nChars * sizeof(gxPoint); pGlyphData->advanceBits = (unsigned long*)p; p += size * sizeof(long); pGlyphData->styles = (gxStyle*)p; p += pGlyphData->nStyles * sizeof(gxStyle); pGlyphData->glyphs = (unsigned char*)p; p += pGlyphData->nChars * sizeof(short); pGlyphData->runs = (short*)p; p += pGlyphData->nStyles * sizeof(short); pGlyphData->text8 = p; p += pGlyphData->byteCount; pGlyphData->fhUserData = (unsigned long*)p; p += pGlyphData->fhUserDataSize; pGlyphData->absPositions = (gxPoint*)p; GXGetGlyphs(theShape, nil, nil, // glyph code data comes from font handler tag pGlyphData->positions, (long*)(pGlyphData->advanceBits), pGlyphData->tangents, nil, pGlyphData->runs, pGlyphData->styles); GXGetTag(fhGlyphTag, nil, pGlyphData->glyphs); // get resolved bytes. if (pGlyphData->fhUserDataSize > 0) // get 2 byte tag, if it is there. GXGetTag(fh2byteTag, nil, pGlyphData->fhUserData); /** We always need absolute positions for level 2 **/ if (pGlobals->params.languageLevel > 1) GXGetGlyphMetrics(theShape, pGlyphData->absPositions, nil, nil); else pGlyphData->absPositions = nil; nrequire(status = GXGetGraphicsError(nil), failed_GetGlyphs); if (pGlyphData->styles[0] == nil) { pGlyphData->styles[0] = GXGetShapeStyle(theShape); }//end if /* fix the non-left justified positions */ nrequire(status = ResolveJustifiedText(hIEGlobals, theShape, pGlyphData), failed_ResolveJustification); /*** Fix vertical style runs positions ***/ nrequire(status = ResolveVerticalText(hIEGlobals, theShape, pGlyphData), failed_Vertical); return(status); failed_Vertical: failed_ResolveJustification: failed_GetGlyphs: { OSErr saveStatus = PSReleaseWorkSpace(hIEGlobals); ncheck(saveStatus); } failed_SetSize: return(status); }//GlyphDataIntoWorkSpace //<FF> #ifdef testappOLDFONTHANDLER extern TIEGlobalsHdl gGlobalHdl; OSErr FHeurFontAvailable( TFontStatistics fDbaseHdl, gxStyle theStyle, char* name, long *child, TMemoryManageResult *memoryState ) { font theFont; *child = 0; theFont = GetStyleFont(theStyle); name[0] = FindFontName(theFont, postscriptFontName, macintoshPlatform, romanScript, englishLanguage, &name[1], nil); /** Make it into a Pascal string **/ return(noErr); } OSErr FHeurBalanceSaveLevel( TFontStatistics fDbaseHdl, TMemoryManageResult *memoryState ) { return(noErr); } OSErr FHeurResolveShapeFonts(TFontStatistics fDbaseHdl, gxShape *theShape) { OSErr status; TGlyphDataRec glyphData; // Block o'glyph data. long currGlyph; // Index of glyph we are currently processing. long styleIndex; // Index of style we are currently processing. Ptr p1, p2; short *glyph; short i,j,k,idx; gxTag textTag; long pltfrm; long size; shapeType theType = GetShapeType(*theShape); if (theType == layoutType) { SetShapeType(*theShape, glyphType); theType = glyphType; }//end if if (theType == textType) { long nBytes; GetText(*theShape, &nBytes, nil, nil); status = PSSetWorkSpaceSize(gGlobalHdl, nBytes); nrequire(status, failed_Text); p1 = *(*gGlobalHdl)->hWorkSpace; GetText(*theShape, nil, p1, nil); textTag = NewTag(kResolveFontTextDataTag, nBytes, p1); SetShapeTags(*theShape, kResolveFontTextDataTag, 1, 0, 1, &textTag); PSReleaseWorkSpace(gGlobalHdl); //DisposeTag(textTag); failed_Text: return(status); }//end if /** Set up the work space for processing the glyphs **/ size = GetGlyphs(*theShape, &glyphData.nChars, nil, nil, nil, nil, &glyphData.nStyles, nil, nil); size += glyphData.nChars + // 8 bit text glyphData.nStyles * sizeof(gxStyle) + // styles; glyphData.nStyles * sizeof(short); // style runs; status = PSSetWorkSpaceSize(gGlobalHdl, size); nrequire(status, failed_GetGlypData); p1 = *(*gGlobalHdl)->hWorkSpace; glyphData.text8 = p1; p1 += glyphData.nChars; glyphData.runs = (short*)p1; p1 += glyphData.nStyles * sizeof(short); glyphData.styles = (gxStyle*)p1; p1 += glyphData.nStyles * sizeof(gxStyle); glyphData.glyphs = p1; GetGlyphs(*theShape, nil, glyphData.glyphs, nil, nil, nil, nil, glyphData.runs, glyphData.styles); j = 0; p1 = glyphData.text8; p2 = (Ptr)glyphData.glyphs; for (i = 0; i < glyphData.nStyles; i++) { if (glyphData.styles[i] == 0) glyphData.styles[i] = GetShapeStyle(*theShape); k = glyphData.runs[i]; pltfrm = GetStylePlatform(glyphData.styles[i], nil, nil); dprintf(notrace, "Platform: %d", pltfrm); if ((pltfrm == macintoshPlatform) && !(GetShapeAttributes(*theShape) & ignorePlatformShape)) { for (idx = 0; idx < k; idx++) *p1++ = *p2++; } else { glyph = (short*)p2; for (idx = 0; idx < k; idx++) { *p1 = (char)(*glyph++ + 0x1D) ; if (*p1 > 0x7F) ++(*p1); ++p1; }//end for p2 += 2 * k; }//end if }//end for textTag = NewTag(kResolveFontTextDataTag, glyphData.nChars, glyphData.text8); SetShapeTags(*theShape, kResolveFontTextDataTag, 1, 0, 1, &textTag); dprintf(notrace, "Address is: %X %X", glyphData.text8, glyphData.glyphs); //DisposeTag(textTag); ncheck(GetGraphicsError(nil)); status = PSReleaseWorkSpace(gGlobalHdl); ncheck(status); failed_GetGlypData: return(status); } #endif //<FF> /********************************************* AnalyzeGlyphPositions: Routine analyzes an array of positions to determine if they are vertical, horizontal, all equal, or all different. positions: pointer to the array of positions to analyze. n: Number of positions to analyze. returned: the positions bias. **********************************************/ TGlyphPosBias AnalyzeGlyphPositions(register gxPoint *positions, register short n); TGlyphPosBias AnalyzeGlyphPositions(register gxPoint *positions, register short n) { gxPoint firstPoint; Boolean allHorizontal, allVertical; #ifdef wierdTiming if (true) return(eAllEqual); #endif firstPoint = positions[0]; allVertical = true; allHorizontal = true; for (--n; n >= 0; --n) { if (firstPoint.x != positions->x) allVertical = false; if (firstPoint.y != positions->y) allHorizontal = false; /** If allVertical and allHorizontal both go to false, then we know it's mixed so break out **/ if (!allVertical && !allHorizontal) break; ++positions; }//end for if (allVertical && allHorizontal) return(eAllEqual); else if (allVertical) return(eAllVertical); else if (allHorizontal) return(eAllHorizontal); else return(eMixed); }//AnalyzeGlyphPositions //<FF> /******************************************* ProcessGlyphGroupDelta: Routine translates a glyph group with advance bits specifying deltas for each character advance to PostScript. nGlyphs: How many glyphs in the group. deltas: Array of deltas for the glyphs. text8: Pointer to the 8 bit data for the group. byteCount: Number of bytes in the 8-bit data. rdParams: pointer to the RDUtil parameter block. addToIndex: 0 for normal, kAddForHexText for text as hex. *********************************************/ OSErr ProcessGlyphGroupDelta(short nGlyphs, gxPoint *deltas, char *text8, long byteCount, TRDParams *rdParams, TGlyphPosBias theBias, long addToIndex); OSErr ProcessGlyphGroupDelta(short nGlyphs, gxPoint *deltas, char *text8, long byteCount, TRDParams *rdParams, TGlyphPosBias theBias, long addToIndex) { OSErr status; gxPoint* pPoint; register short j; /** Get pen in correct position for 1st glyph in group. **/ if ((deltas[0].x != 0) | (deltas[0].y != 0)) { status = DoRmoveto(rdParams, &(deltas[0])); nrequire(status, failed_Output); }//end if /*** Draw the glyphs ****/ if (theBias == eAllEqual) { if ((deltas[1].x == 0) && (deltas[1].y == 0)) { //if deltas are zero, just do show. rdParams->resIndex = addToIndex + kShow; } else { //If they are all equal, do ashow. nrequire(status = DoPoint(rdParams, &(deltas[1])), failed_Output); // Output the delta. rdParams->resIndex = addToIndex + kAshow; }//end if } else { // do kshow with rmoveto's. pPoint = deltas + nGlyphs - 1; if (theBias == eAllHorizontal) { rdParams->resIndex = kDoFixed; for (j = nGlyphs-2; j >= 0; --j) { // Do all X's but the first point, first was handled by rmoveto nrequire(status = RDResPrintf(rdParams, pPoint->x), failed_Output); --pPoint; }//end for nrequire(status = RDResPrintf(rdParams, deltas[1].y), failed_Output); // Output the constant Y value on the stack.(y[1]) rdParams->resIndex = addToIndex + kKshowRH; } else if (theBias == eAllVertical) { rdParams->resIndex = kDoFixed; for (j = nGlyphs-2; j >= 0; --j) { // Do all Y's but the first point, first was handled by rmoveto nrequire(status = RDResPrintf(rdParams, pPoint->y), failed_Output); --pPoint; }//end for nrequire(status = RDResPrintf(rdParams, deltas[1].x), failed_Output); // Output the constant X value on the stack. (x[1]) rdParams->resIndex = addToIndex + kKshowRV; } else { rdParams->resIndex = kDoPoint; for (j = nGlyphs-2; j >= 0; --j) { // Do all but the first point. nrequire(status = RDResPrintf(rdParams, pPoint), failed_Output); --pPoint; }//end for rdParams->resIndex = addToIndex + kKshowR; }//end if }//end if //Output the string using whichever script procedure set above in rdParams->resIndex status = RDResPrintf(rdParams, text8, byteCount); ncheck(status); failed_Output: return(status); }//ProcessGlyphGroupDelta //<FF> /******************************************* ProcessStyleRun: Routine translates a style run from a glyph shape into PostScript hIEGlobals: the Global storage handle. startGlyph: Index of the first glyph in the style run. theStyle: style of style run to process. glyphData: Pointer to the glyph data block. runLength: Number of glyphs in style/tangent run. pTangent: tangent vector for this run. addToIndex: 0 for normal, kAddForHexText for text as hex. *********************************************/ OSErr ProcessStyleRun(TIEGlobalsHdl hIEGlobals, short startGlyph, gxStyle theStyle, TGlyphDataRec *glyphData, short runLength, gxPoint* pTangent, long addToIndex); OSErr ProcessStyleRun(TIEGlobalsHdl hIEGlobals, short startGlyph, gxStyle theStyle, TGlyphDataRec *glyphData, short runLength, gxPoint* pTangent, long addToIndex) { OSErr status; TRDParams *rdParams; register unsigned long *advLong; register unsigned long advMask; long i; long firstGlyphInGroup; // Index of first glyph in the group. long groupLength; // size of a glyph group (all adv bits the same) Boolean advIsOne; // True if current advance bit is one. Boolean currAdv; char *text8; // Pointer to the 8-bit data. long byteCount; // Number of bytes in the 8-bit datay. gxPoint* posGroup; // pointer into positions for group. TGlyphPosBias theBias; // Bias for the glyph positions. gxPoint nextDelta; // delta of first glyph of next run rdParams = (*hIEGlobals)->pRDParams; advLong = glyphData->advLong; advMask = glyphData->advMask; /** Set up text style in graphics state **/ status = _TextStylePrimitive(hIEGlobals, theStyle, pTangent); nrequire(status, failed_Font); /******************************* Find all of the glyph groups in the style run and output them. A glyph group is a run of glyphs that have the same advance bit value ********************************/ firstGlyphInGroup = startGlyph; NEXTBIT(advIsOne, advLong, advMask); // Find out if the 1st advance is 1 or zero. i = 0; while(i < runLength) { groupLength = 1; // Group length is one glyph so far. while ( ++i < runLength) { // ++i, we're about to look at next glyph's bit. NEXTBIT(currAdv, advLong, advMask); // Get the next advance bit value. if (currAdv != advIsOne) // Break out of loop if adv bit is different. break; ++groupLength; // If we didn't fall out yet, grow group. }//while /******************** Find out how many bytes are necessary for this run. For 8-bit text it will be the same as groupLength. *********************/ text8 = (char*)(glyphData->currByte); if (glyphData->fhUserDataSize == 0) { byteCount = groupLength; } else { // Traverse the bits to figure it out. register long bcnt = 0; register Boolean theBit; byteCount = 0; while (bcnt < groupLength) { NEXTBIT(theBit, glyphData->twoByteLong, glyphData->twoByteMask); if (theBit) byteCount += 2; else ++byteCount; ++bcnt; }//end while }//end if glyphData->currByte += byteCount; // Point to the next byte for subsequent text. posGroup = &(glyphData->positions[firstGlyphInGroup]); /* Compute the delta of the first glyph after this group to pass to group routines */ { long nextCharIndex = firstGlyphInGroup + groupLength; nextDelta.x = nextDelta.y = 0; // init to zero. if (nextCharIndex < glyphData->nChars) // if not last if ( ! BITTST(glyphData->advanceBits, nextCharIndex) ) // and next advance bit is zero nextDelta = glyphData->positions[nextCharIndex]; // make it next value in array } /** Output the glyph group **/ if (advIsOne) { theBias = AnalyzeGlyphPositions(posGroup, groupLength); if ((*hIEGlobals)->params.languageLevel == 1) { status = ProcessGlyphGroupPosL1(groupLength, posGroup, text8, byteCount, rdParams, theBias, addToIndex); } else { posGroup = &(glyphData->absPositions[firstGlyphInGroup]); theBias = AnalyzeGlyphPositions(posGroup, groupLength); status = ProcessGlyphGroupPosL2(hIEGlobals, groupLength, posGroup, text8, byteCount, rdParams, theBias, addToIndex, &nextDelta); }//end if nrequire(status, failed_ProcessGroup); } else { // Advance bits were zero /**** For deltas, we don't care if the first is different from group since it is handled by an explicit rmoveto before the ashow or kshow *****/ theBias = AnalyzeGlyphPositions(posGroup + 1, groupLength - 1); if ( ((*hIEGlobals)->params.languageLevel == 1) || (theBias == eAllEqual) ) { status = ProcessGlyphGroupDelta(groupLength, posGroup, text8, byteCount, rdParams, theBias, addToIndex); } else { /** If they were not all equal and we are level-2 then we can use x(y)show for speed **/ posGroup = &(glyphData->absPositions[firstGlyphInGroup]); theBias = AnalyzeGlyphPositions(posGroup, groupLength); // reanalyze whole group this time - for use of absolute positions. status = ProcessGlyphGroupPosL2(hIEGlobals, groupLength, posGroup, text8, byteCount, rdParams, theBias, addToIndex, &nextDelta); }//end if nrequire(status, failed_ProcessGroup); }//end if advIsOne = currAdv; firstGlyphInGroup += groupLength; }//end while glyphData->advLong = advLong; // Save last values for next style run. glyphData->advMask = advMask; failed_ProcessGroup: failed_Font: return(status); }//ProcessStyleRun //<FF> /****************************************** GlyphPrimitive: Translate a glyph shape to PostScript. *******************************************/ OSErr _GlyphPrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions) { #pragma unused(geomOptions) OSErr status; TGlyphDataRec glyphData; // Block o'glyph data. long currGlyph; // Index of glyph we are currently processing. long styleIndex; // Index of style we are currently processing. gxPoint* pTangent; // Pointer into tangent vectors. gxStyle* pStyle; // Pointer into styles array. short *pRunSize; // size of current style run. short tanRunSize; // size of run of tangenets. short nGlyphsDone; // Number of glyphs done so far in style run. short remaining; // Number of glyphs remaining in run. short stackLimit; // Usable stack limit for glyph shapes. long addToIndex = 0; // Add to res index for hex if ((*hIEGlobals)->params.renderOptions & gxNeedsHexOption) addToIndex = kAddForHexText; /****** Usable stack space for glyph shapes (positions for glyphs are potentially put on stack) Evil Heuristic: take real stack limit divided by 2 because we need to push x,y subtract 50 to allow for any procedures that may be executed due to text face, etc… *******/ stackLimit = ( (*hIEGlobals)->params.opStackLimit >> 1 ) - 50; ncheck((stackLimit < 0)); /** Set up the work space for processing the glyphs **/ status = GlyphDataIntoWorkSpace(hIEGlobals, theShape, &glyphData); nrequire(status, failed_GetGlypData); glyphData.advLong = glyphData.advanceBits; // Get first long full o'advances. glyphData.advMask = 0x80000000; // Initialize the advance bit mask. glyphData.twoByteLong = glyphData.fhUserData; // Get first long full o'two byte flags. glyphData.twoByteMask = 0x80000000; // Initialize mask to two-byte bits. glyphData.currByte = glyphData.glyphs; // Point to first glyph in shape. currGlyph = 0; // Initialize glyph index. /********************************************** The first advance bit will always be 1, because we need at least one position for the glyph shape. Check the 2nd advance bit. If it is 0 and the delta is 0, then do a moveto now for the first position and reset the 1st advance bit to be 0. This Eliminates having the first glyph group being an absolute poistioned single character which is a dumb thing to have. ************************************************/ if ( ((*(glyphData.advLong) & 0x40000000) == 0) && (glyphData.nChars > 1) ) { status = DoMoveto((*hIEGlobals)->pRDParams, glyphData.positions); nrequire(status, failed_DoMoveto); *(glyphData.advLong) &= 0x7FFFFFFF; // Clear the first advance bit glyphData.positions[0].x = 0; // Set first delta to be 0,0 glyphData.positions[0].y = 0; }//end if /*** Process Each of the style runs: Within each style run, find runs of equal tangent vectors and process seperately ***/ pRunSize = glyphData.runs; pTangent = glyphData.tangents; pStyle = glyphData.styles; for (styleIndex = 0; styleIndex < glyphData.nStyles; styleIndex++) { nGlyphsDone = 0; remaining = *pRunSize; while (nGlyphsDone < *pRunSize) { tanRunSize = 1; while ( (pTangent->x == (pTangent + 1)->x ) && (pTangent->y == (pTangent + 1)->y ) && (tanRunSize < remaining) && (tanRunSize < stackLimit) ) { ++pTangent; ++tanRunSize; }//end while status = ProcessStyleRun(hIEGlobals, currGlyph, *pStyle, &glyphData, tanRunSize, pTangent, addToIndex); nrequire(status, failed_ProcssRun); ++pTangent; // Move to next tangent. nGlyphsDone += tanRunSize; currGlyph += tanRunSize; remaining -= tanRunSize; }//end while ++pStyle; ++pRunSize; }//end for failed_ProcssRun: failed_DoMoveto: /** Release the work space **/ { register OSErr saveStatus = PSReleaseWorkSpace(hIEGlobals); ncheck(saveStatus); if (status == noErr) status = saveStatus; } failed_GetGlypData: return(status); }//GlyphPrimitive //<FF> /****************************************** TextPrimitive: Translate a text shape to PostScript. *******************************************/ OSErr _TextPrimitive(TIEGlobalsHdl hIEGlobals, gxShape theShape, TgeometryOptions geomOptions) { OSErr status; gxStyle theStyle; long byteCnt; // How many bytes of text. char *pText; // Pointer to the text. gxPoint textLoc; // Where to draw it. TIEGlobalsPtr pGlobals; TRDParams* pRDParams; gxPoint tangent = {ff(1), ff(0)}; // text always has 1 0 tangent vector. gxTag textTag; // tag where modified char codes are stored. long addToIndex = 0; // Add to res index for hex if ( GXGetText(theShape, nil, nil, nil) == 0) // see if we have to do anything? return(noErr); /** Size > 0, process the text **/ theStyle = GXGetShapeStyle(theShape); /** If the style is vertical, we must convert it to a glyph shape and process it that way **/ if (GXGetStyleTextAttributes(theStyle) & gxVerticalText) { gxShape workShape; /* If the shape is shared, work on the copy */ if (GXGetShapeOwners(theShape) > 1) { workShape = GXCopyToShape(nil, theShape); nrequire(status = GXGetGraphicsError(nil), failed_copyIt); } else { workShape = theShape; }//end if GXSetShapeType(workShape, gxGlyphType); nrequire(status = GXGetGraphicsError(nil), failed_SetShapeType); /* Process the glyph shape */ status = _GlyphPrimitive(hIEGlobals, workShape, geomOptions); nrequire(status, failed_GlyphPrimitive); /* dispose of the working copy if necessary */ if (workShape != theShape) GXDisposeShape(workShape); } else { /* Process the text shape */ if ((*hIEGlobals)->params.renderOptions & gxNeedsHexOption) addToIndex = kAddForHexText; pGlobals = *hIEGlobals; pRDParams = pGlobals->pRDParams; // Grab the parameter block for ResPrintf. GXGetText(theShape, nil, nil, &textLoc); // Get the text shape's position. /** Get the text data from the tag created by the Font Handler **/ GXGetShapeTags(theShape, fhTextDataTag, 1, 1, &textTag); ncheck(GXGetGraphicsError(nil)); GXLockTag(textTag); pText = (char*)((char*)GXGetTagStructure(textTag, &byteCnt) - tagStructureBugOffset); /** Set the font in the current graphics state **/ nrequire(status = _TextStylePrimitive(hIEGlobals, theStyle, &tangent), failed_Font); /** If the style is not left justified, adjust it’s position here **/ if( GXGetStyleJustification(theStyle) != gxLeftJustify ) { long count = GXGetGlyphMetrics(theShape, nil, nil, nil); gxPoint *positions; status = PrNewPtr((Ptr*)&positions, (count + 1) * sizeof(gxPoint)); nrequire(status, failed_NewPtr); GXGetGlyphMetrics(theShape, positions, nil, nil); textLoc = positions[0]; DisposePtr( (Ptr)positions ); } /* Move the current point for the shape. */ nrequire(status = DoMoveto(pRDParams, &textLoc), failed_Moveto); /** Do the show **/ pRDParams->resIndex = kShow + addToIndex; nrequire(status = RDResPrintf(pRDParams, pText, byteCnt), failed_Show); failed_Show: failed_NewPtr: failed_Moveto: failed_Font: GXUnlockTag(textTag); }//end if if (status == noErr) status = GXGetGraphicsError(nil); ncheck(status); failed_GlyphPrimitive: failed_SetShapeType: failed_copyIt: return(status); }//TextPrimitive